package net.lab0.fractal.fractals.mandelbrot;


public class MandelbrotComputationThread
extends Thread
{
    private static int                     threadNumber = 0;
    private MultithreadedMandelbrotFractal parent;
    private int                            compH;
    private int                            compW;
    private double                         xStep;
    private double                         yStep;
    private double                         xCenter;
    private double                         yCenter;
    private double                         viewportWidth;
    private double                         viewportHeight;
    private int                            slice;
    private int                            slices;
    private boolean                        stop         = false;
    private boolean                        go           = false;
    
    public MandelbrotComputationThread(MultithreadedMandelbrotFractal parent)
    {
        super("MandelbrotComputationThread-" + threadNumber);
        threadNumber++;
        this.parent = parent;
    }
    
    @Override
    public void run()
    {
        while (!stop)
        {
            if (go)
            {
                go = false;
                computationBlock();
                parent.notifyFinished(this);
            }
            else
            {
                try
                {
                    Thread.sleep(250);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
    
    protected void computationBlock()
    {
        long maxIteration = parent.getMaxIteration();
        for (int y = slice; y < compH; y += slices)
        {
            if (parent.restartTest())
            {
                break;
            }
            parent.pauseTest();
            
            parent.setProgress((float) y / (float) compH, this);
            
            for (int x = 0; x < compW; x++)
            {
                long iter = 0;
                double x0, x1, y0, y1;
                x0 = x1 = xCenter - viewportWidth / 2 + xStep * x;
                y0 = y1 = yCenter + viewportHeight / 2 - yStep * y;
                // cardiod + 1st bulb test, cf wiki
                double q = (x0 - 0.25) * (x0 - 0.25) + y0 * y0;
                boolean inside = (q * (q + (x0 - 0.25)) < y0 * y0 * 0.25) || (((x0 + 1) * (x0 + 1) + y0 * y0) < 0.0625);
                if (!inside)
                {
                    while (x1 * x1 + y1 * y1 <= 4 && iter < maxIteration)
                    {
                        double tempX = x1 * x1 - y1 * y1 + x0;
                        y1 = 2 * x1 * y1 + y0;
                        x1 = tempX;
                        iter++;
                    }
                }
                else
                {
                    iter = maxIteration;
                }
                parent.pixels[x][y] = iter;
            }
        }
    }
    
    public void setGo(boolean go)
    {
        if (go == true)
        {
            // System.out.println("notify " + Thread.currentThread().getName());
            this.go = go;
        }
    }
    
    public int getSlice()
    {
        return slice;
    }
    
    public void setSlice(int slice)
    {
        this.slice = slice;
    }
    
    public float getSlices()
    {
        return slices;
    }
    
    public void setSlices(int slices)
    {
        this.slices = slices;
    }
    
    public void setCompH(int compH)
    {
        this.compH = compH;
    }
    
    public void setCompW(int compW)
    {
        this.compW = compW;
    }
    
    public void setxStep(double xStep)
    {
        this.xStep = xStep;
    }
    
    public void setyStep(double yStep)
    {
        this.yStep = yStep;
    }
    
    public void setxCenter(double xCenter)
    {
        this.xCenter = xCenter;
    }
    
    public void setyCenter(double yCenter)
    {
        this.yCenter = yCenter;
    }
    
    public void setViewportWidth(double viewportWidth)
    {
        this.viewportWidth = viewportWidth;
    }
    
    public void setViewportHeight(double viewportHeight)
    {
        this.viewportHeight = viewportHeight;
    }
    
    public void setStop(boolean stop)
    {
        this.stop = stop;
    }
    
}
